package com.ddpt.platform.common.expression;

import cn.hutool.json.JSONUtil;
import com.ddpt.platform.common.expression.enums.ConditionBusinessTypeEnum;
import com.ddpt.platform.common.expression.enums.ConditionJoinOperatorEnum;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;

import java.util.*;

/**
 * 将对象类型的规则引擎转换成表达式
 */
public class ConditionParser {

    /**
     * 将规则对象解析为表达式
     * @param entity 规则对象
     * @return  表达式
     */
    public static String parseToExpression(ConditionEntity entity){
        if(entity == null){
            return "";
        }
        if(StringUtils.isBlank(entity.getExpression()) && CollectionUtils.isEmpty(entity.getChildren())){
            return "";
        }
        if(CollectionUtils.isEmpty(entity.getChildren())){
            return "("+entity.getExpression()+")";
        }
        List<ConditionEntity> children = entity.getChildren();
        StringBuilder result = new StringBuilder();
        result.append("(");
        deepGroup(children,result,entity.getJoinOperator().operate);
        result.append(")");
        return result.toString();
    }

    private static void deepGroup(List<ConditionEntity> children,StringBuilder group, String operate){
        ConditionJoinOperatorEnum lastJoinType = null;
        for (ConditionEntity item : children) {
            if(StringUtils.isBlank(item.getExpression()) && CollectionUtils.isEmpty(item.getChildren())){
                return ;
            }
            if(CollectionUtils.isEmpty(item.getChildren())){
                group.append(item.getExpression());
            }else{
                StringBuilder childrenGroup = new StringBuilder();
                childrenGroup.append("(");
                deepGroup(item.getChildren(),childrenGroup, item.getJoinOperator().operate);
                childrenGroup.append(")");
                group.append(childrenGroup);
            }
            lastJoinType = item.getJoinOperator();
            group.append(operate);
        }

        if(lastJoinType != null){
            group.delete(group.lastIndexOf(operate),group.length());
        }
    }

    /**
     * 获取规则引擎使用到的所有属性或事件key
     */
    public static List<String> getPropertyKeys(ConditionEntity entity){
        Map<ConditionBusinessTypeEnum,Set<String>> keys = new HashMap<>();
        List<ConditionEntity> children = entity.getChildren();
        recursionPropertyKeys(children,keys);
        Set<String> result = new HashSet<>();
        keys.values().forEach(result::addAll);
        return new ArrayList<>(result);
    }

    /**
     * 获取规则引擎使用到的所有属性或事件key
     */
    public static Map<ConditionBusinessTypeEnum,Set<String>> getPropertyKeysWithBusiness(ConditionEntity entity){
        Map<ConditionBusinessTypeEnum,Set<String>> keys = new HashMap<>();
        putBusinessTypeKeys(entity,keys);
        List<ConditionEntity> children = entity.getChildren();
        recursionPropertyKeys(children,keys);
        return keys;
    }

    private static void recursionPropertyKeys(List<ConditionEntity> conditions, Map<ConditionBusinessTypeEnum,Set<String>> keys){
        if(CollectionUtils.isEmpty(conditions)){
            return ;
        }
        conditions.parallelStream().forEach(conditionEntity -> {
            putBusinessTypeKeys(conditionEntity,keys);
            recursionPropertyKeys(conditionEntity.getChildren(),keys);
        });
    }

    private static void putBusinessTypeKeys(ConditionEntity entity,Map<ConditionBusinessTypeEnum,Set<String>> keys){
        List<ConditionKey> conditionKeys = entity.getKeys();
        if(!CollectionUtils.isEmpty(conditionKeys)){
            conditionKeys.forEach(key -> {
                ConditionBusinessTypeEnum businessType = key.getBusinessType();
                keys.putIfAbsent(businessType,new HashSet<>());
                keys.get(businessType).add(key.getKey());
            });
        }
    }

    /**
     * 获取规则引擎使用到的所有属性或事件key
     */
    public static Map<ConditionBusinessTypeEnum,Map<String, String>> getPropertyKeysWithBusiness2(ConditionEntity entity){
        Map<ConditionBusinessTypeEnum,Map<String, String>> keys = new HashMap<>();
        putBusinessTypeKeys2(entity,keys);
        List<ConditionEntity> children = entity.getChildren();
        recursionPropertyKeys2(children, keys);
        return keys;
    }

    private static void recursionPropertyKeys2(List<ConditionEntity> conditions, Map<ConditionBusinessTypeEnum,Map<String, String>> keys){
        if(CollectionUtils.isEmpty(conditions)){
            return ;
        }
        conditions.parallelStream().forEach(conditionEntity -> {
            putBusinessTypeKeys2(conditionEntity,keys);
            recursionPropertyKeys2(conditionEntity.getChildren(),keys);
        });
    }

    private static void putBusinessTypeKeys2(ConditionEntity entity,Map<ConditionBusinessTypeEnum,Map<String, String>> keys){
        List<ConditionKey> conditionKeys = entity.getKeys();
        if(!CollectionUtils.isEmpty(conditionKeys)){
            conditionKeys.forEach(key -> {
                ConditionBusinessTypeEnum businessType = key.getBusinessType();
                keys.putIfAbsent(businessType,new HashMap<>());
                keys.get(businessType).put(key.getKey(), key.getObj());
                /*if(StringUtils.isNotBlank(key.getObj()) && !keys.get(businessType).get(key.getKey()).equals(key.getObj())){
                    keys.get(businessType).put(key.getKey()+"$$", key.getObj());
                }else {
                    keys.get(businessType).put(key.getKey(), key.getObj());
                }*/
            });
        }
    }

    public static void main(String[] args) {
        String oringal = "{\"joinOperator\":\"Or\",\"children\":[{\"joinOperator\":\"Or\",\"children\":[{\"key\":\"groupLimit\",\"joinOperator\":\"And\",\"value\":{\"exit\":1,\"groupId\":[3,5],\"groupName\":[\"测试客群01\",\"测试客群\"]},\"keys\":[{\"businessType\":\"user_group\",\"key\":\"userGroupAny$$_3__5\"}],\"expression\":\"$_user_group.userGroupAny$$_3__5==true\"}]},{\"joinOperator\":\"And\",\"children\":[{\"key\":\"activityLimit\",\"joinOperator\":\"And\",\"value\":{\"connection\":\">=\",\"groupId\":9,\"keyValue\":1,\"indicators\":\"actPartinCount\",\"startTime\":0,\"endTime\":1,\"timeValue\":\"0\",\"timeType\":\"1\",\"propertyType\":0,\"actName\":\"兔兔盲盒\",\"indicsName\":\"活动参与次数\"},\"keys\":[{\"businessType\":\"act\",\"key\":\"actPartinCount$$_9\"}],\"expression\":\"$_act.actPartinCount$$_9>='1'\"}]},{\"joinOperator\":\"And\",\"children\":[{\"key\":\"timeLimit\",\"joinOperator\":\"And\",\"value\":{\"type\":1,\"day\":\"1,2,3,4,5\",\"startTime\":\"14:00:00\",\"endTime\":\"15:00:00\"},\"expression\":\"(($_system.weekDay==1||$_system.weekDay==2||$_system.weekDay==3||$_system.weekDay==4||$_system.weekDay==5)&&($_system.time>140000&&$_system.time<150000))\",\"keys\":[{\"businessType\":\"system\",\"key\":\"weekDay\"},{\"businessType\":\"system\",\"key\":\"time\"}]}]}]}";
        String expression = parseToExpression(JSONUtil.toBean(oringal, ConditionEntity.class));
        System.out.println(expression);
    }
}
